--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Commit e330e7b3eefb2ee2743a2b314ee57d1556c2f270
Parents : 8b021f4
Author : Ivan <ivan@quad4.io>
Signature : Signature validation error
Date : 2026-04-16T03:50:57-05:00
chore(android): remove legacy Gitea workflow and update GitHub Actions for Android build process, including new dependencies and custom recipe support
Changes
3 files changed, 79 insertions(+), 122 deletions(-)
Diff
diff --git a/.gitea/workflows/android-build.yml b/.gitea/workflows/android-build.yml
deleted file mode 100644
index d4b3bd21..00000000
--- a/.gitea/workflows/android-build.yml
+++ /dev/null
@@ -1,122 +0,0 @@
-name: Build Android APK
-
-on:
- workflow_dispatch:
- inputs:
- version:
- description: "Release version (e.g., v1.0.0)"
- required: false
- type: string
-
-permissions:
- contents: write
- packages: write
-
-jobs:
- build-android:
- name: Build Android APK
- runs-on: ubuntu-latest
- steps:
- - name: Clone Repo
- run: |
- set -eu
- SERVER="${GITEA_SERVER_URL:-${GITHUB_SERVER_URL:-}}"
- REPO="${GITEA_REPOSITORY:-${GITHUB_REPOSITORY:-}}"
- if [ -z "$SERVER" ] || [ -z "$REPO" ]; then
- echo "Checkout: set GITEA_SERVER_URL/GITEA_REPOSITORY or GITHUB_SERVER_URL/GITHUB_REPOSITORY" >&2
- exit 1
- fi
- if [ -n "${GITEA_TOKEN:-}" ] || [ -n "${GITHUB_TOKEN:-}" ]; then
- TOKEN="${GITEA_TOKEN:-$GITHUB_TOKEN}"
- git config --global credential.helper "!f() { echo username=x-access-token; echo password=${TOKEN}; }; f"
- fi
- git clone "${SERVER}/${REPO}.git" .
- git checkout "${GITHUB_SHA}"
-
- - name: Determine version
- id: version
- run: |
- if [ "${{ github.event_name }}" = "workflow_dispatch" ] && [ -n "${{ github.event.inputs.version }}" ]; then
- echo "version=${{ github.event.inputs.version }}" >> $GITHUB_OUTPUT
- elif [[ "${{ github.ref }}" == refs/tags/* ]]; then
- VERSION="${GITHUB_REF#refs/tags/}"
- echo "version=${VERSION}" >> $GITHUB_OUTPUT
- else
- SHORT_SHA=$(git rev-parse --short HEAD)
- echo "version=${SHORT_SHA}" >> $GITHUB_OUTPUT
- fi
-
- - name: Setup JDK
- run: sh scripts/ci/setup-java.sh 17
-
- - name: Setup Node.js
- run: sh scripts/ci/setup-node.sh 24
-
- - name: Setup Python
- run: sh scripts/ci/setup-python.sh 3.14
-
- - name: Install Poetry
- run: python3 -m pip install --upgrade pip poetry>=2.0.0
-
- - name: Setup pnpm
- run: sh scripts/ci/setup-pnpm.sh
-
- - name: Install system dependencies
- run: |
- sh scripts/ci/exec-priv.sh apt-get update
- sh scripts/ci/exec-priv.sh apt-get install -y patchelf libopusfile0 ffmpeg espeak-ng cmake ninja-build clang pkg-config
-
- - name: Setup Task
- run: sh scripts/ci/setup-task.sh
-
- - name: Sync versions
- run: |
- . scripts/ci/ci-node-path.sh
- node scripts/sync_version.js
-
- - name: Install dependencies
- run: |
- . scripts/ci/ci-node-path.sh
- task install
-
- - name: Build Frontend and Prepare Android
- run: |
- . scripts/ci/ci-node-path.sh
- task android:prepare
-
- - name: Build Android APK
- run: |
- cd android
- ./gradlew assembleDebug
- env:
- JAVA_HOME: /opt/java
-
- - name: Prepare release assets
- run: |
- mkdir -p release-assets
- find android/app/build/outputs/apk/debug -name "*.apk" -exec cp {} release-assets/MeshChatX-${{ steps.version.outputs.version }}-debug.apk \;
-
- cd release-assets
- for file in *; do
- if [ -f "$file" ]; then
- sha256sum "$file" | tee "${file}.sha256"
- fi
- done
-
- - name: Upload APK artifact
- uses: https://git.quad4.io/actions/upload-artifact@ff15f0306b3f739f7b6fd43fb5d26cd321bd4de5 # v3.2.1
- with:
- name: meshchatx-android-apk
- path: release-assets/*
-
- - name: Create Release
- if: github.event_name == 'push' || github.event_name == 'workflow_dispatch'
- uses: https://git.quad4.io/actions/gitea-release-action@4875285c0950474efb7ca2df55233c51333eeb74 # v1
- with:
- api_url: ${{ secrets.GITEA_API_URL }}
- gitea_token: ${{ secrets.GITEA_TOKEN }}
- title: Android Build ${{ steps.version.outputs.version }}
- tag: ${{ steps.version.outputs.version }}-android
- files: "release-assets/*"
- draft: false
- prerelease: false
diff --git a/.github/workflows/android-build.yml b/.github/workflows/android-build.yml
index 429f61d3..69822c15 100644
--- a/.github/workflows/android-build.yml
+++ b/.github/workflows/android-build.yml
@@ -63,6 +63,18 @@ jobs:
with:
python-version: ${{ env.PYTHON_VERSION }}
+ - name: Install Android wheel build dependencies
+ run: |
+ sudo apt-get update
+ sudo apt-get install -y build-essential cmake pkg-config patchelf
+
+ - name: Install Rust toolchain
+ run: |
+ curl -sSfL https://sh.rustup.rs -o rustup-init.sh
+ chmod +x rustup-init.sh
+ ./rustup-init.sh -y --profile minimal --default-toolchain stable
+ echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
+
- name: Build Android wheels
run: bash scripts/build-android-wheels-local.sh --python-minor "${PYTHON_VERSION}" --chaquopy-ref "${CHAQUOPY_REF}"
diff --git a/scripts/build-android-wheels-local.sh b/scripts/build-android-wheels-local.sh
index 2dddf0f8..31aa70bb 100755
--- a/scripts/build-android-wheels-local.sh
+++ b/scripts/build-android-wheels-local.sh
@@ -573,5 +573,72 @@ with zipfile.ZipFile(src, "r") as zin, zipfile.ZipFile(dst, "w", compression=zip
PY
fi
+CUSTOM_RECIPES_DIR="${ROOT_DIR}/android/chaquopy-recipes"
+if [[ -d "${CUSTOM_RECIPES_DIR}" ]]; then
+ echo "Building custom Android recipes from ${CUSTOM_RECIPES_DIR}"
+ for RECIPE_SRC in "${CUSTOM_RECIPES_DIR}"/*; do
+ if [[ ! -d "${RECIPE_SRC}" ]]; then
+ continue
+ fi
+
+ RECIPE_NAME="$(basename "${RECIPE_SRC}")"
+ RECIPE_DST="${PYPIDIR}/packages/${RECIPE_NAME}-local"
+ rm -rf "${RECIPE_DST}"
+ mkdir -p "${RECIPE_DST}"
+ cp -a "${RECIPE_SRC}/." "${RECIPE_DST}/"
+
+ read -r PACKAGE_NAME PACKAGE_VERSION < <("${VENV_DIR}/bin/python" - <<PY
+from pathlib import Path
+import re
+meta = Path("${RECIPE_DST}/meta.yaml").read_text()
+name = re.search(r'(?m)^\\s*name:\\s*"?(.*?)"?\\s*$', meta)
+version = re.search(r'(?m)^\\s*version:\\s*"?(.*?)"?\\s*$', meta)
+if not name or not version:
+ raise SystemExit("Failed parsing name/version from meta.yaml")
+print(name.group(1), version.group(1))
+PY
+)
+
+ echo "Building ${PACKAGE_NAME} ${PACKAGE_VERSION} from recipe ${RECIPE_NAME}"
+ for abi in ${ABI_LIST//,/ }; do
+ abi_tag="${abi//-/_}"
+ echo "Building ${PACKAGE_NAME} ${PACKAGE_VERSION} for ${abi}"
+ "${VENV_DIR}/bin/python" "${PYPIDIR}/build-wheel.py" \
+ --python "${PYTHON_MINOR}" \
+ --api-level "${API_LEVEL}" \
+ --abi "${abi}" \
+ "${RECIPE_DST}"
+
+ WHEEL_GLOB="${PYPIDIR}/dist/${PACKAGE_NAME}"/*android_"${API_LEVEL}"_"${abi_tag}".whl
+ if ! ls ${WHEEL_GLOB} >/dev/null 2>&1; then
+ echo "Missing wheel output for ${PACKAGE_NAME} ${PACKAGE_VERSION} ${abi}" >&2
+ exit 1
+ fi
+ cp -f ${WHEEL_GLOB} "${OUT_DIR}/"
+ done
+
+ if [[ "${PACKAGE_NAME}" == "cryptography" ]]; then
+ "${VENV_DIR}/bin/python" - <<PY
+import zipfile
+from pathlib import Path
+
+version = "${PACKAGE_VERSION}"
+out_dir = Path("${OUT_DIR}")
+for wheel in sorted(out_dir.glob(f"cryptography-{version}-*.whl")):
+ tmp = wheel.with_suffix(".tmp.whl")
+ with zipfile.ZipFile(wheel, "r") as zin, zipfile.ZipFile(tmp, "w", compression=zipfile.ZIP_DEFLATED) as zout:
+ for item in zin.infolist():
+ data = zin.read(item.filename)
+ if item.filename.endswith(".dist-info/METADATA"):
+ text = data.decode("utf-8")
+ text = text.replace("Requires-Dist: cffi>=2.0.0 ;", "Requires-Dist: cffi>=1.15.1 ;")
+ data = text.encode("utf-8")
+ zout.writestr(item, data)
+ tmp.replace(wheel)
+PY
+ fi
+ done
+fi
+
echo "Done."
echo "Built wheels in: ${OUT_DIR}"
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────